home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / netlog-1.02 / nstat / nstat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-18  |  9.9 KB  |  386 lines

  1. /* nstat - network statistics collector
  2.  *
  3.  * nstat [-i interface][-t time period (sec)]
  4.  */
  5.  
  6. #include    <stdio.h>
  7. #include    <signal.h>
  8. #include      <fcntl.h>
  9. #include    <malloc.h>
  10. #include    <errno.h>
  11. #include    <time.h>
  12.  
  13. #include    <sys/file.h>
  14. #include    <sys/ioctl.h>
  15. #include    <sys/types.h>
  16. #include    <sys/time.h>
  17. #include    <sys/socket.h>
  18. #include      <sys/stropts.h>
  19. #include      <net/if.h>
  20. #include    <net/nit.h>
  21. #include      <net/nit_if.h>
  22. #include      <net/nit_buf.h>
  23. #include      <netinet/in.h>
  24. #include    <netinet/if_ether.h>
  25.  
  26. #define    MAX_CHUNK    1024*100    /* maximum chunk size returned */
  27. #define    TIMEOUT        2    /* chunk timeout in seconds */
  28. #define    MAX_DATA_LEN    60
  29. #define    PKT_TIMESTAMPS    0x1  /* packet headers contain timestamps */
  30. #define    PKT_HEADERS    0x2  /* packets contain network-layer headers */
  31. #define DEBUG         0
  32.  
  33. struct nit_packet {       
  34.     struct nit_bufhdr        header;
  35.     u_long                   nit_if_drops,
  36.                              nit_if_origlen;
  37.     struct pkt {    /* simplified - ignores option fields */
  38.         /* ethernet */
  39.         u_char          edst[6];
  40.         u_char          esrc[6];
  41.        u_short         etype;
  42.         /* IP */
  43.         u_char          vl;
  44.         u_char          tos;
  45.         u_short         tlen;
  46.         u_short         ident;
  47.         u_short         foff;
  48.         u_char          time;
  49.         u_char          proto;
  50.         u_short         ipcksum;
  51.         u_char          isrc[4];/* can't use long, for alignment - sigh */
  52.         u_char          idst[4];/* can't use long, for alignment - sigh */
  53.         /* tcp */
  54.         u_short         tsrc;
  55.         u_short         tdst;
  56.         u_char          seq[4]; /* can't use long, for alignment - sigh */
  57.         u_char          ack[4];    /* can't use long, for alignment - sigh */
  58.         u_char          ofr;
  59.         u_char          code;
  60.         u_short         window;
  61.         u_short         tcpcksum;
  62.         u_short         urg;
  63.         u_char            data[1];
  64.     } pkt;
  65. };
  66.  
  67. u_char        *buffer;
  68. u_long        *etypep, *udpportp, *tcpportp;
  69. u_long        *etypeb, *udpportb, *tcpportb;
  70. u_long      *ipprotop, *ipprotob;
  71. u_long        ipoptions = 0;
  72. u_long        total = 0;
  73. u_long        totalb = 0;
  74. u_long        n802 = 0;
  75. u_long        runt = 0;
  76. u_long        dropped = 0;
  77. u_long        cur_drop = 0;
  78. int        nit;
  79. int        promiscuous = 1;
  80. char         interface[10] = "le0";
  81. int          set_time = 3600;
  82. struct timeval    starttimer, stoptimer;
  83. int        debug = DEBUG;
  84.  
  85. void    init();
  86. void    cleanup ();
  87. void    report();
  88. void    collect ();
  89. void    setoptions ();
  90. void    usage ();
  91. void     dump_pkt();
  92.  
  93. /*  Main routine setup everything, then call collect  */
  94. main (argc,argv) 
  95. int argc;
  96. char **argv;
  97. {
  98.     setoptions(argc,argv);
  99.     init();
  100.     nit = insert_tap(interface);
  101.     signal(SIGINT,cleanup);
  102.     collect();     /* does not return */
  103. }
  104.  
  105. void    setoptions (argc,argv)
  106. int argc;
  107. char **argv;
  108. {
  109.     if(argc==2)
  110.         usage("argc = 2");
  111.     while(argc>2) {
  112.         if(argv[argc-2][0]!='-')
  113.             usage("argv missing -");
  114.         switch(argv[argc-2][1]){
  115.             case 'i': {strcpy(interface,argv[argc-1]);
  116.                    break;}
  117.             case 't': {set_time = atoi(argv[argc-1]);
  118.                    break;}
  119.             default : {usage("bad switch");}
  120.         }
  121.         argc -= 2;
  122.     }
  123. }
  124.  
  125. void    usage (e)
  126. char *e;
  127. {
  128.   fprintf(stderr,"%s\n",e);
  129.   fputs("Usage: nstat \n",stderr);
  130.   fputs("             [-i interface]\t(default \"le0\")\n",stderr);
  131.   fputs("             [-t set_secs]\t(default 3600)\n",stderr);
  132.   exit (1);
  133. }
  134.  
  135. void init()
  136. {
  137.     buffer = (u_char *)calloc((unsigned)(MAX_CHUNK), sizeof(char));
  138.     etypep = (u_long *)calloc((unsigned)65536,sizeof(u_long));    
  139.     etypeb = (u_long *)calloc((unsigned)65536,sizeof(u_long));    
  140.     tcpportp = (u_long *)calloc((unsigned)65536,sizeof(u_long));    
  141.     tcpportb = (u_long *)calloc((unsigned)65536,sizeof(u_long));    
  142.     udpportp = (u_long *)calloc((unsigned)65536,sizeof(u_long));    
  143.     udpportb = (u_long *)calloc((unsigned)65536,sizeof(u_long));
  144.     ipprotop = (u_long *)calloc((unsigned)256,sizeof(u_long));    
  145.     ipprotob = (u_long *)calloc((unsigned)256,sizeof(u_long));    
  146. }
  147.  
  148. /*  Insert tap - setup NIT socket */
  149. int     insert_tap (if_name)
  150. char    *if_name;
  151. {
  152.     int                 if_fd;
  153.     u_long              tempval;
  154.     u_int        temp2;
  155.     struct strioctl     si;
  156.     struct ifreq        ifr;
  157.     struct timeval      timeout;
  158.  
  159.     if ((if_fd = open("/dev/nit", O_RDONLY)) < 0) {
  160.         perror ("opening nit stream");
  161.         exit (1);
  162.     }
  163.     /* Arrange to get discrete messages from the stream */
  164.     if (ioctl( if_fd, I_SRDOPT, (char *)RMSGD) != 0) {
  165.          perror("I_SRDOPT");
  166.          exit (1);
  167.     }
  168.     /* Push and configure NIT buffering module */
  169.     if (ioctl(if_fd, I_PUSH, "nbuf") != 0) {
  170.          perror("I_PUSH nbuf");
  171.          exit (1);
  172.     }
  173.  
  174.     si.ic_timout = INFTIM;
  175.     timeout.tv_sec   = (long)(TIMEOUT);
  176.     timeout.tv_usec  = 0;
  177.     si.ic_cmd = NIOCSTIME;            
  178.     si.ic_len = sizeof timeout;
  179.     si.ic_dp  = (char *)&timeout;
  180.     if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
  181.          perror("NIOCSTIME");
  182.          exit (1);
  183.     }
  184.     si.ic_cmd = NIOCSCHUNK;
  185.     temp2   = (u_int)(MAX_CHUNK);
  186.     si.ic_len = sizeof temp2;
  187.     si.ic_dp  = (char *)&temp2;
  188.     if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
  189.          perror("NIOCSCHUNK");
  190.          exit (1);
  191.     } 
  192.     /* Configure the NIT device, binding it to the proper interface */
  193.     strncpy (ifr.ifr_name, if_name, sizeof (ifr.ifr_name));
  194.     ifr.ifr_name[sizeof ifr.ifr_name -1] = ' ';
  195.     si.ic_cmd = NIOCBIND;
  196.     si.ic_len = sizeof ifr;
  197.     si.ic_dp  = (char *)𝔦
  198.     if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
  199.          perror(": NIOCSBIND");
  200.          exit (1);
  201.     }
  202.  
  203.     /* Set snapshot length */
  204.     /*  currently commented out, as it causes the machine to hang!!!
  205.      *    tempval = (u_long) (MAX_DATA_LEN);
  206.      *   si.ic_cmd = NIOCSSNAP;
  207.      *   si.ic_len = sizeof tempval;
  208.      *   si.ic_dp  = (char *)&tempval;
  209.      *   if (ioctl(if_fd, I_STR, (char *)&si) != 0) {
  210.      *        perror("NIOCSSNAP");
  211.      *        exit (1);
  212.      *   }
  213.      */
  214.  
  215.     tempval = NI_DROPS | NI_LEN;
  216.     if (promiscuous)
  217.        tempval |= NI_PROMISC;
  218.     si.ic_cmd = NIOCSFLAGS;
  219.     si.ic_len = sizeof tempval;
  220.     si.ic_dp  = (char *)&tempval;
  221.     if (ioctl(if_fd, I_STR, (char *)&si) !=0) { 
  222.          perror("NIOCSFLAGS");
  223.          exit(1);
  224.     }
  225.     ioctl(if_fd, I_FLUSH, (char *)FLUSHR);
  226.     return if_fd;
  227. }
  228.  
  229. void    collect ()
  230. {
  231.     register unsigned char      *bp;
  232.     register unsigned char      *bufend;
  233.     register struct nit_packet  *hdrp;
  234.     int                         tail;
  235.     int                plen,nlen;
  236.  
  237.     gettimeofday (&starttimer, (struct timezone *)NULL);
  238.     while (1) {
  239.     while ((tail = read(nit,buffer, MAX_CHUNK)) <= 0);
  240.         bp     = buffer;
  241.         bufend = bp + tail;
  242.         while (bp < bufend) {
  243.             hdrp  = (struct nit_packet *)bp;
  244.         plen = hdrp->header.nhb_msglen;
  245.         nlen = hdrp->header.nhb_totlen;
  246.             bp += nlen;
  247.         if(plen >= MAX_DATA_LEN+8)
  248.             countpacket(hdrp);
  249.         else
  250.         runt++;
  251.         }
  252.         gettimeofday (&stoptimer, (struct timezone *)NULL);
  253.         if ( (stoptimer.tv_sec - starttimer.tv_sec) > set_time) {
  254.         report();
  255.         gettimeofday(&starttimer, (struct timezone *) NULL);
  256.     }
  257.           
  258.     }
  259. }
  260.                              
  261. countpacket(p) 
  262. struct nit_packet *p;
  263. {
  264.     int ipoptlen;
  265.     cur_drop = p -> nit_if_drops - dropped;
  266.     total++;
  267.     totalb += p->nit_if_origlen;
  268.     if(p->pkt.etype <1515) {
  269.     n802++;
  270.     return;
  271.     }
  272.     if(debug)
  273.         dump_pkt((char *)&(p->pkt));
  274.     etypep[p->pkt.etype]++;
  275.     etypeb[p->pkt.etype] += p->nit_if_origlen;
  276.     if(p->pkt.etype == ETHERTYPE_IP) {
  277.         ipprotop[(unsigned int)p->pkt.proto]++;
  278.         ipprotob[(unsigned int)p->pkt.proto] += p->nit_if_origlen;
  279.         ipoptlen = (((p->pkt.vl)&0x0f)-5)*2;
  280.         if(ipoptlen != 0) {
  281.         ipoptions++;
  282.         printf("# ipoptlen %d\n",ipoptlen);
  283.         }
  284.  
  285.         if (p->pkt.proto == IPPROTO_TCP) {
  286.         tcpportp[*(&(p->pkt.tsrc)+ipoptlen)]++;
  287.             tcpportp[*(&(p->pkt.tdst)+ipoptlen)]++;
  288.         tcpportb[*(&(p->pkt.tsrc)+ipoptlen)] += p->nit_if_origlen;
  289.         tcpportb[*(&(p->pkt.tdst)+ipoptlen)] += p->nit_if_origlen;
  290.         } 
  291.         else if (p->pkt.proto == IPPROTO_UDP){
  292.         udpportp[*(&(p->pkt.tsrc)+ipoptlen)]++;
  293.         udpportp[*(&(p->pkt.tdst)+ipoptlen)]++;
  294.         udpportb[*(&(p->pkt.tsrc)+ipoptlen)] += p->nit_if_origlen;
  295.         udpportb[*(&(p->pkt.tdst)+ipoptlen)] += p->nit_if_origlen;
  296.         }
  297.     }
  298. }
  299.  
  300. void report()
  301. {
  302.     int i;
  303.     char  t1[40],t2[40];
  304.  
  305.     strcpy(t1,ctime(&starttimer.tv_sec));
  306.     strcpy(t2,ctime(&stoptimer.tv_sec));
  307.     printf ("#Start %s#Stop  %s",t1,t2);
  308.     printf("#%lu packets, %lu bytes, %lu 802.3, %lu runt, %lu missed, %lu ipopt.\n",
  309.         total, totalb, n802, runt, cur_drop,ipoptions);
  310.     total = 0;
  311.     totalb = 0;
  312.     n802 = 0;
  313.     runt = 0;
  314.     ipoptions = 0;
  315.     dropped += cur_drop;
  316.  
  317.     for(i=0;i<65536;i++) {
  318.     if(etypep[i]>0){
  319.         printf("e %x\t# %lu\tb %lu\n",i,
  320.         etypep[i],etypeb[i]);
  321.         etypep[i] = 0;
  322.         etypeb[i] = 0;
  323.     }
  324.     } 
  325.     for(i=0;i<256;i++) {
  326.     if(ipprotop[i] >0) {
  327.         printf("i %d\t# %lu\tb %lu\n",i,
  328.         ipprotop[i],ipprotob[i]);
  329.         ipprotop[i] = 0;
  330.         ipprotob[i] = 0;
  331.     }
  332.     }
  333.     for(i=0;i<65536;i++) {
  334.     if(tcpportp[i]>0) {
  335.         printf("t %d\t# %lu\tb %lu\n",i,
  336.         tcpportp[i],tcpportb[i]);
  337.         tcpportp[i] = 0;
  338.         tcpportb[i] = 0;
  339.     }
  340.     } 
  341.     for(i=0;i<65536;i++) {
  342.     if(udpportp[i]>0) {
  343.         printf("u %d\t# %lu\tb %lu\n",i,
  344.         udpportp[i],udpportb[i]);
  345.         udpportp[i] = 0;
  346.         udpportb[i] = 0;
  347.     }
  348.     } 
  349.     fflush(stdout);
  350. }
  351.  
  352.                                     
  353. void    cleanup ()
  354. {
  355.     close (nit);
  356.     report();
  357.     exit (0);
  358. }
  359.  
  360. void dump_pkt(b)
  361. char *b;
  362. {
  363.     char s[32],d[32];
  364.     int i1,i2;
  365.     struct pkt *p;
  366.     extern char *ether_ntoa();
  367.     extern char *inet_ntoa();
  368.  
  369.     p = (struct pkt *) b;
  370.  
  371.     strcpy(s, ether_ntoa((struct ether_addr *) p->esrc));
  372.     strcpy(d, ether_ntoa((struct ether_addr *) p->edst));
  373.     printf("Ethernet src %s dst %s type %d\n",s,d,p->etype);
  374.  
  375.     strcpy(s, inet_ntoa((struct inet_addr *) p->isrc));
  376.     strcpy(d, inet_ntoa((struct inet_addr *) p->idst));
  377.     printf("IP src %s dst %s length %d ident %d\n",
  378.         s,d, (int) p->tlen, (int) p->ident);
  379.  
  380.     bcopy(p->seq,&i1,4);
  381.     bcopy(p->ack,&i2,4);
  382.     printf("TCP src port %d dst port %d seq %d ack %d\n",
  383.         (int)p->tsrc, (int)p->tdst, i1, i2);
  384.     printf("Code %d Data 0x%x\n",(int)p->code,(int)p->data[0]);
  385. }
  386.